package com.arithmeticEveryDay.greed;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

/*

4 10
0 1 1
1 0 1
1 2 2
2 1 2
2 3 100
3 2 100
3 0 1
0 3 1
1 3 3
3 1 3



 */
public class MinSpaningTree {
    
    static InOut3 io = new InOut3();
    int vertexCount, edgeCount;
    PriorityQueue<Edge> queue;
    DisjointSet set;
    
    public MinSpaningTree() {
        vertexCount = io.nextInt();
        edgeCount = io.nextInt();
        queue = new PriorityQueue<Edge>();
        set = new DisjointSet(vertexCount);
        for (int i = 0; i < edgeCount; i++) {
            queue.add(new Edge(io.nextInt(), io.nextInt(), io.nextInt()));
        }
    }
    
    /*
    
    Kruskal算法是从最短的边出发，然后是次短边，次次短边...边与边不能形成环，直到所有顶点都被连接，最小生成树就形成了
    
     */
    private void kruskal() {
        List<Edge> list = new ArrayList<Edge>();
        // vertexCount个顶点，只需要vertexCount-1条边
        while (list.size() < vertexCount - 1 && !queue.isEmpty()) {
            Edge edge = queue.poll();
            // io.out.print(edge + " ");
            int iRoot = set.findRoot(edge.i);
            int jRoot = set.findRoot(edge.j);
            if (iRoot != jRoot) {
                set.union(iRoot, jRoot);
                list.add(edge);
            }
        }
        // io.out.println();
        io.out.println(list.toString());
        io.out.println(Arrays.toString(set.parent));
        io.out.println(Arrays.toString(set.size));
    }
    
    public static void main(String[] args) {
        MinSpaningTree m = new MinSpaningTree();
        m.kruskal();
        io.out.flush();
    }


}
class DisjointSet {
    int[] parent;
    int[] size;
    public DisjointSet(int n) {
        parent = new int[n];
        size = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
    public int findRoot(int i) {
        if (parent[i] == i) {
            return i;
        } else {
            parent[i] = findRoot(parent[i]);
            return parent[i];
        }
    }
    // 祖先合并，需保证传入的i和j是祖先
    public void union(int i, int j) {
        // 短链接在长链祖先上，保证长链不会因为继续变长而让findRoot更慢
        if (size[i] >= size[j]) {
            parent[j] = i;
            size[i]++;
        } else if (size[i] < size[j]) {
            parent[i] = j;
            size[j]++;
        }
    }
}
class Edge implements Comparable<Object> {
    
    public int i, j, w;
    public Edge(int i, int j, int w) {
        this.i = i;
        this.j = j;
        this.w = w;
    }
    
    @Override
    public int compareTo(Object o) {
        Edge to = (Edge) o;
        if (this.w > to.w) {
            return 1;
        } else if (this.w == to.w) {
            return 0;
        }
        return -1;
    }
    
    public String toString() {
        return "(" + i + ", " + j + ", " + w + ")";
    }
    
}

class InOut3 {
    BufferedReader br;
    StringTokenizer tok;
    PrintWriter out;
    InOut3() {
        br = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(new OutputStreamWriter(System.out));
    }
    public boolean hasNext() {
        while (tok == null || !tok.hasMoreElements()) {
            try {
                tok = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                return false;
            }
        }
        return true;
    }
    public String next() {
        if (hasNext()) {
            return tok.nextToken();
        }
        return null;
    }
    public int nextInt() {
        return Integer.parseInt(next());
    }
    
}